<?php
class svcenv
{
    private static $TIMEOUT=60;

    private $addr;
    private $sock;

    public function __construct($site="")
    {/*{{{*/
        $this->addr="";
        $this->sock=null;

        if(!empty($site))
        {
            $loc=get_cfg_var("svcenv_addr_".$site);
            if(empty($loc))
            {
                $loc=get_cfg_var("svcenv_addr");
            }
        }
        else
        {
            $loc=get_cfg_var("svcenv_addr");
        }
        if(!empty($loc))
        {
            $arr=parse_url($loc);
            $this->addr=gethostbyname($arr['host']).":".
                intval($arr['port']);
        }
        else
        {
            errlog::add("%s|%s: svcenv_addr invalid",
                    basename(__FILE__), __METHOD__);
        }
    }/*}}}*/

    public function __destruct()
    {/*{{{*/
        if(!is_null($this->sock))
        {
            socket_close($this->sock);
        }
    }/*}}}*/

    private function _call($request, &$respond)
    {/*{{{*/
        $respond="";
        if(is_null($this->sock))
        {
            $timeout=5;
            $sock=sock::connect($this->addr, $timeout);
            if($sock === false)
            {
                errlog::add("%s|%s: connect to svcenv fail",
                    basename(__FILE__), __METHOD__);
                para::put_item($respond, SOAR_ERR_COMM_FAIL);
                return false;
            }
            $this->sock=$sock;
        }

        $timeout=self::$TIMEOUT;
        if(sock::send($this->sock, $request, $timeout) == false)
        {
            errlog::add("%s|%s: send svc(%s) request to svcenv fail",
                    basename(__FILE__), __METHOD__, $svc);
            para::put_item($respond, SOAR_ERR_COMM_FAIL);
            return false;
        }
        if(sock::recv($this->sock, $respond, $timeout) == false)
        {
            errlog::add("%s|%s: recv svc(%s) response to svcenv fail",
                    basename(__FILE__), __METHOD__, $svc);
            para::put_item($respond, SOAR_ERR_COMM_FAIL);  
            return false;
        }

        return true;
    }/*}}}*/

    public function call($svc, $request, &$respond)
    {/*{{{*/
        para::put_item($msg, "CALL", $svc);
        $msg.=$request;
        return self::_call($msg, $respond);
    }/*}}}*/

    public function callnode($node, $svc, $request, &$respond)
    {/*{{{*/
        para::put_item($msg, "CALLNODE", $node, $svc);
        $msg.=$request;
        return self::_call($msg, $respond);
    }/*}}}*/

    public function close()
    {/*{{{*/
        if(is_null($this->sock)) return false;
        para::put_item($request, "CLOSE");
        $res=self::_call($request, $respond);
        socket_close($this->sock);
        $this->sock=null; 
        return true;
    }/*}}}*/

    public function begin()
    {/*{{{*/
        if(!is_null($this->sock))
        {
            errlog::add("%s|%s: ".
                    "without ending former trans, begin new trans",
                    basename(__FILE__), __METHOD__);
            socket_close($this->sock);
            $this->sock=null;
        }
    }/*}}}*/

    public function commit()
    {/*{{{*/
        if(is_null($this->sock)) return false;
        para::put_item($request, "COMMIT");
        return self::_call($request, $respond);
        //socket_close($this->sock);
        //$this->sock=null; 
        return true;
    }/*}}}*/

    public function abort()
    {/*{{{*/
        if(is_null($this->sock)) return false;
        para::put_item($request, "ABORT");
        return self::_call($request, $respond);
        //socket_close($this->sock);
        //$this->sock=null; 
    }/*}}}*/

    public function session()
    {/*{{{*/
        include_once "session.inc";
        $h=new session($this);
        return $h;
    }/*}}}*/

    public function secure()
    {/*{{{*/
        include_once "secure.inc";
        $h=new secure($this);
        return $h;
    }/*}}}*/

    public function mailfwd()
    {/*{{{*/
        include_once "mailfwd.inc";
        $h=new mailfwd($this);
        return $h;
    }/*}}}*/

    public function confirm()
    {/*{{{*/
        include_once "confirm.inc";
        $h=new confirm($this);
        return $h;
    }/*}}}*/
}
?>
